/******************************************************************************
 * Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *****************************************************************************/
#ifndef CORE_H
#define CORE_H
#include "nds_intrinsic.h"
#include "sys.h"

#define read_csr(reg)       __nds__csrr(reg)
#define write_csr(reg, val) __nds__csrw(val, reg)
#define swap_csr(reg, val)  __nds__csrrw(val, reg)
#define set_csr(reg, bit)   __nds__csrrs(bit, reg)
#define clear_csr(reg, bit) __nds__csrrc(bit, reg)

/*
 * Inline nested interrupt entry/exit macros
 */
/* Svae/Restore macro */
#define save_csr(r)    long __##r = read_csr(r)
#define restore_csr(r) write_csr(r, __##r)
/* Support PowerBrake (Performance Throttling) feature */

#define save_mxstatus()    save_csr(NDS_MXSTATUS)
#define restore_mxstatus() restore_csr(NDS_MXSTATUS)

/* Nested IRQ entry macro : Save CSRs and enable global interrupt. */
#define core_save_nested_context()                                                                                    \
    save_csr(NDS_MEPC); save_csr(NDS_MSTATUS); save_mxstatus(); set_csr(NDS_MSTATUS, 1 << 3)

/* Nested IRQ exit macro : Restore CSRs */
#define core_restore_nested_context()                                                                                 \
    clear_csr(NDS_MSTATUS, 1 << 3);                                                                                   \
    restore_csr(NDS_MSTATUS); restore_csr(NDS_MEPC); restore_mxstatus()

#define fence_iorw __nds__fence(FENCE_IORW, FENCE_IORW)

typedef enum {
    FLD_FEATURE_PREEMPT_PRIORITY_INT_EN = BIT(0),
    FLD_FEATURE_VECTOR_MODE_EN = BIT(1),
} feature_e;

/**
 * @brief Disable interrupts globally in the system.external, timer and software interrupts.
 * @return  r - the value of machine interrupt enable(MIE) register.
 * @note  this function must be used when the system wants to disable all the interrupt.
 */
static inline unsigned int core_interrupt_disable(void)
{
    unsigned int r = read_csr(NDS_MIE);
    clear_csr(NDS_MIE, BIT(3) | BIT(7) | BIT(11));
    return r;
}

/**
 * @brief restore interrupts globally in the system. external,timer and software interrupts.
 * @param[in]  en - the value of machine interrupt enable(MIE) register before disable.
 * @return     0
 * @note this function must be used when the system wants to restore all the interrupt.
 */
static inline unsigned int core_restore_interrupt(unsigned int en)
{
    set_csr(NDS_MIE, en);
    return 0;
}

/**
 * @brief enable interrupts globally in the system.
 * @return  none
 */
static inline void core_interrupt_enable(void)
{
    set_csr(NDS_MSTATUS, 1 << 3);
    set_csr(NDS_MIE, (1 << 11) | (1 << 7) | (1 << 3));
}
#endif
